package org.jflame.context.ratelimiter;

import org.jflame.commons.exception.BusinessException;
import org.jflame.context.spring.aop.BaseMakableAspect;

import java.util.concurrent.TimeUnit;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.core.Ordered;

/**
 * aop限流处理切面,适合粗粒度的计数限流
 * 
 * @author charles.zhang
 */
@Aspect
public class RequestRateAspect extends BaseMakableAspect implements Ordered {

    private RateLimiter limiter;

    public RequestRateAspect() {
        limiter = new InMemoryRateLimiter();
    }

    public RequestRateAspect(RateLimiter limiter) {
        if (limiter != null) {
            this.limiter = limiter;
        } else {
            this.limiter = new InMemoryRateLimiter();
        }
    }

    @Before("@annotation(limiterAnnotatation)")
    public void beforeAdvice(JoinPoint joinPoint, RequestRate limiterAnnot) {
        String requestId = parseInovkeKey(limiterAnnot.key(), joinPoint);
        long interval = TimeUnit.SECONDS.convert((long) limiterAnnot.interval(), limiterAnnot.timeUnit());
        boolean isExceed = limiter.checkLimit(requestId, limiterAnnot.threshold(), interval);
        if (isExceed) {
            throw new BusinessException("访问太频繁,请稍候再试");
        }
    }

    public void setLimiter(RateLimiter limiter) {
        this.limiter = limiter;
    }

    @Override
    public int getOrder() {
        return Ordered.HIGHEST_PRECEDENCE;
    }

}
